package com.gen.jpa.util;

/**
 * @Author meiyubin
 * @Date 2024/7/24
 * @DESC
 */

import com.gen.jpa.entity.ColumnModel;
import com.gen.jpa.entity.TableModel;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.swing.filechooser.FileSystemView;
import java.beans.PropertyVetoException;
import java.io.*;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Jpa代码辅助工具类
 */
@Component
public class JpaAutoCodeUtils {
   // 包名
    private final static String CLASS_PATH = "com.cloume.maps.fips";
    //生成文件路径目录
    private final static String GENERATE_FILE_PATH = "/Users/herman/Desktop/文档/autoCode";
    //文件尾缀
    private final static String DTO_SUFFIX = "DTO";
    private final static String VO_SUFFIX = "VO";
    private final static String REPOSITORY_SUFFIX = "Repository";
    private final static String SERVICE_SUFFIX = "Service";
    private final static String SERVICE_IMPL_SUFFIX = "ServiceImpl";
    private final static String CONTROLLER_SUFFIX = "Controller";
    //模板名称
    private final static String ENTITY_FTL = "entity.ftl";
    private final static String VO_FTL = "entityVO.ftl";
    private final static String DTO_FTL = "entity_dto.ftl";
    private final static String REPOSITORY_FTL = "repository.ftl";
    private final static String SERVICE_FTL = "service.ftl";
    private final static String SERVICE_IMPL_FTL = "service_impl.ftl";
    private final static String CONTROLLER_FTL = "controller.ftl";
    //过滤字段
    private final static String FILTER_FIELDS = "id,updateBy,updateTime,checkState,checkBy,checkTime";

    private JpaAutoCodeUtils() {
    }

    /**
     * 生成所有数据库表jpa代码
     *
     * @param tablePrefix 表格前缀
     * @throws PropertyVetoException
     * @throws SQLException
     */
    public static void allCodeGenerator(String tablePrefix) throws PropertyVetoException, SQLException {
        List<TableModel> tableList = DbUtils.buildTableModelList(tablePrefix);
        for (TableModel tableModel : tableList) {
            buildMetadata(tableModel,CLASS_PATH);
        }
    }

    /**
     * 根据表名生成指定jpa代码
     *
     * @param tableName   表格名
     * @param tablePrefix 表格前缀
     * @throws PropertyVetoException
     * @throws SQLException
     */
    public static void codeGenerator(String tableName, String tablePrefix) throws PropertyVetoException, SQLException {
        TableModel tableModel = DbUtils.buildTableModel(tablePrefix, tableName);
        buildMetadata(tableModel,CLASS_PATH);

    }
    public static void codeGenerator(List<String> tableName, String tablePrefix) throws PropertyVetoException, SQLException {
        if (tableName!=null&&tableName.size()>0){
            List<TableModel> tableModels = DbUtils.buildTableModel(tablePrefix, tableName);
            tableModels.forEach(tableModel -> {
                buildMetadata(tableModel,CLASS_PATH);
            });
        }

    }

    /**
     * 构建元数据
     *
     * @param tableModel 表格模型
     */
    private static void buildMetadata(TableModel tableModel,String classPath ) {
        String entityName = tableModel.getEntityName();
        Map<String, Object> map = new HashMap<>();
        FileSystemView view = FileSystemView.getFileSystemView();
        if(StringUtils.isEmpty(classPath)){
         classPath = view.getHomeDirectory().getPath() + "\\autoCode";
        classPath = classPath.replace("C:\\", "").replace("\\", ".");
        }
        Set<String> fieldTypes = tableModel.getColumnList().stream().map(ColumnModel::getJavaType).collect(Collectors.toSet());
        map.put("fieldTypes", fieldTypes);
        map.put("classPath", classPath);
        map.put("classPathShort", classPath);
        map.put("tableName", tableModel.getTableName());
        map.put("tableDesc", tableModel.getTableDesc());
        List<ColumnModel> fieldList = tableModel.getColumnList().stream().filter(column -> !FILTER_FIELDS.contains(column.getHumpColumnName())).collect(Collectors.toList());
        map.put("fieldList", fieldList);
        List<ColumnModel> collect = tableModel.getColumnList().stream().filter(column -> column.isPrimary()).collect(Collectors.toList());
        if(collect.size()>0){
        map.put("idType", collect.get(0).getJavaType());
       }
        map.put("Entity", entityName);
        map.put(DTO_SUFFIX, entityName + DTO_SUFFIX);
        map.put(VO_SUFFIX, entityName + VO_SUFFIX);
        map.put(REPOSITORY_SUFFIX, entityName + REPOSITORY_SUFFIX);
        map.put(SERVICE_SUFFIX, entityName + SERVICE_SUFFIX);
        map.put(SERVICE_IMPL_SUFFIX, entityName + SERVICE_IMPL_SUFFIX);
        map.put(CONTROLLER_SUFFIX, entityName + CONTROLLER_SUFFIX);
        map.put("List", "List");
        map.put("Long", "Long");
        map.put("PageVo", "PageVo");

        processTemplate(map, ENTITY_FTL, entityName + ".java");
        processTemplate(map, DTO_FTL, entityName + DTO_SUFFIX + ".java");
        processTemplate(map, VO_FTL, entityName + VO_SUFFIX + ".java");
        processTemplate(map, REPOSITORY_FTL, entityName + REPOSITORY_SUFFIX + ".java");
        processTemplate(map, SERVICE_FTL, entityName + SERVICE_SUFFIX + ".java");
        processTemplate(map, SERVICE_IMPL_FTL, entityName + SERVICE_IMPL_SUFFIX + ".java");
        processTemplate(map, CONTROLLER_FTL, entityName + CONTROLLER_SUFFIX + ".java");
    }

    /**
     * 模板处理
     *
     * @param dataMap  模板中的参数键值
     * @param ftlName  模板ftl文件
     * @param fileName 生成的文件名称
     */
    private static void processTemplate(Map<String, Object> dataMap, String ftlName, String fileName) {
        String classPath =(String) dataMap.get("classPath");
        //根据ftlName名改变classPath
        changeClassPath(ftlName,dataMap);
        //创建freeMarker配置实例
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
        Writer out = null;
        try {
            //获取模版路径
            configuration.setDirectoryForTemplateLoading(new File("src/main/resources/ftl"));
            //加载模版文件
            Template template = configuration.getTemplate(ftlName);
            //生成数据
            FileSystemView view = FileSystemView.getFileSystemView();
            String path="";
            if (StringUtils.isEmpty(GENERATE_FILE_PATH)){
             path = view.getHomeDirectory().getPath() + "/autoCode";}
            else{
                path=GENERATE_FILE_PATH;
            }

            String fileClassPath = genFilePath(path,ftlName);
            System.out.println(fileClassPath);
            File newDir = new File(fileClassPath);
            File newFile = new File(newDir, fileName);
            if (!newDir.exists()) {
                newDir.mkdirs();
                newFile.createNewFile();
            }
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile)));
            //输出文件
            template.process(dataMap, out);
            dataMap.put("classPath",classPath);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != out) {
                    out.flush();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }

    private static void changeClassPath(String ftlName, Map<String, Object> dataMap) {
        String classPath =(String) dataMap.get("classPath");
        switch (ftlName) {
            case ENTITY_FTL:
                 dataMap.put("classPath",classPath + ".enity");
                 break;
            case DTO_FTL:
                dataMap.put("classPath",classPath + ".dto");
                break;
            case REPOSITORY_FTL:
                dataMap.put("classPath",classPath + ".repository");
                break;
            case SERVICE_FTL:
                dataMap.put("classPath",classPath + ".service");
                break;
            case SERVICE_IMPL_FTL:
                dataMap.put("classPath",classPath  + ".service.impl");
                break;
            case CONTROLLER_FTL:
                dataMap.put("classPath",classPath +   ".controller");
                break;
            default:
                System.out.println("1");;
        }
    }

    private static String genFilePath(String path, String ftlName) {
        switch (ftlName) {
            case ENTITY_FTL:
                return path + "/enity";
            case DTO_FTL:
                return path + "/dto";
            case VO_FTL:
                return path + "/vo";
            case REPOSITORY_FTL:
                return path + "/repository";
            case SERVICE_FTL:
                return path + "/service";
            case SERVICE_IMPL_FTL:
                return path + "/service/impl";
            case CONTROLLER_FTL:
                return path + "/controller";
            default:
                return path;
        }
    }
}
